package com.zy.ems.common.http;

import java.io.File;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

/**
 * http请求工具类。
 * 
 * @author Luffy
 *
 */
public class HttpClientUtil {
    private static Logger LOG = LoggerFactory.getLogger(HttpClientUtil.class);

    private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 1000;

    private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 200;

    /**
     * httpClient客户端
     */
    private static CloseableHttpClient httpClient;

    /**
     * 连接池管理器
     */
    private static PoolingHttpClientConnectionManager connManager;

    /**
     * Spring提供的访问Rest服务的客户端
     */
    private static RestTemplate restTemplate;

    /**
     * 初始化
     */
    static {
        // 连接池管理器
        connManager = new PoolingHttpClientConnectionManager();
        // 连接池最大连接数
        connManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
        // 每个路由最大连接数
        connManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);

        // http请求配置信息
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(50000).setSocketTimeout(50000)
                .setConnectionRequestTimeout(50000)
                .setCookieSpec(CookieSpecs.STANDARD).build();

        httpClient = HttpClients.custom().setConnectionManager(connManager)
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManagerShared(true).build();
        LOG.info("Initializing CloseableHttpClient");

        // 添加内容转换器
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        messageConverters
                .add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
        messageConverters.add(new FormHttpMessageConverter());
        messageConverters.add(new MappingJackson2HttpMessageConverter());

        restTemplate = new RestTemplate(
                new HttpComponentsClientHttpRequestFactory(httpClient));
        restTemplate.setMessageConverters(messageConverters);
        LOG.info("Initializing RestTemplate");
    }

    static CloseableHttpClient getHttpClient() {
        return httpClient;
    }

    static RestTemplate getRestTemplate() {
        return restTemplate;
    }

    /**
     * 处理GET请求。
     * 
     * @param url
     * @return
     */
    public static String executeGet(String url) {
        return executeGet(url, null);
    }

    /**
     * 处理GET请求。
     * 
     * @param url
     * @param params
     * @return
     */
    public static String executeGet(String url, Map<String, String> params) {
        return executeGet(url, null, params);
    }

    /**
     * 处理GET请求。
     * 
     * @param url
     * @param headers
     * @param params
     * @return
     */
    public static String executeGet(String url, Map<String, String> headers,
            Map<String, String> params) {
        return execute(url, HttpGet.METHOD_NAME, headers, params, null);
    }

    /**
     * 处理POST请求。
     * 
     * @param url
     * @return
     */
    public static String executePost(String url) throws URISyntaxException {
        return executePost(url, null);
    }

    /**
     * 处理POST请求。
     * 
     * @param url
     * @param params
     * @return
     */
    public static String executePost(String url, Map<String, String> params) {
        return executePost(url, null, params);
    }

    public static String executePost(String url, Map<String, String> params,
            Charset charSet) {
        return executePost(url, null, params, charSet);
    }

    /**
     * 处理POST请求。
     * 
     * @param url
     * @param headers
     * @param params
     * @return
     */
    public static String executePost(String url, Map<String, String> headers,
            Map<String, String> params, Charset charSet) {
        return execute(url, HttpPost.METHOD_NAME, headers, params, charSet);
    }

    /**
     * 处理POST请求。
     * 
     * @param url
     * @param headers
     * @param params
     * @return
     */
    public static String executePost(String url, Map<String, String> headers,
            Map<String, String> params) {
        return execute(url, HttpPost.METHOD_NAME, headers, params, null);
    }

    /**
     * 上传文件。
     * 
     * @param url
     * @param partName
     * @param filePath
     * @param params
     * @param contentType 上传文件类型
     * @return
     */
    public static String uploadFile(String url, String partName,
            String filePath, Map<String, String> params, String contentType) {
        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
        // 上传的文件
        File file = new File(filePath);
        FileBody fileBody = new FileBody(file, ContentType.create(contentType));
        entityBuilder.addPart(partName, fileBody);
        // 设置请求参数
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> param : params.entrySet()) {
                entityBuilder.addTextBody(param.getKey(), param.getValue());
            }
        }
        // 构建http请求
        RequestBuilder requestBuilder = RequestBuilder.post(url)
                .setCharset(Consts.UTF_8);
        // 设置请求体
        requestBuilder.setEntity(entityBuilder.build());
        // 执行http请求
        return doExecute(requestBuilder.build(), Consts.UTF_8);
    }

    /**
     * 处理HTTP请求。
     * 
     * @param uri
     * @param method
     * @param headers
     * @param params
     * @return
     * @throws URISyntaxException
     */
    public static String execute(String uri, String method,
            Map<String, String> headers, Map<String, String> params,
            Charset charSet) {

        // 字符集
        if (charSet == null) {
            charSet = Consts.UTF_8;
        }
        // 构建http请求
        RequestBuilder requestBuilder = RequestBuilder.create(method)
                .setUri(uri).setCharset(charSet);
        // 设置请求参数
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> param : params.entrySet()) {
                requestBuilder.addParameter(param.getKey(), param.getValue());
            }
        }
        // 设置请求头
        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> header : headers.entrySet()) {
                requestBuilder.addHeader(header.getKey(), header.getValue());
            }
        }
        // 执行http请求
        return doExecute(requestBuilder.build(), charSet);
    }

    /**
     * 执行Http请求。
     * 
     * @param request
     * @return
     */
    private static String doExecute(HttpUriRequest request, Charset charSet) {
        // 执行请求
        try (CloseableHttpResponse response = getHttpClient()
                .execute(request);) {
            // 处理请求结果
            HttpEntity entity = response.getEntity();
            String result = "";
            if (entity != null) {
                result = EntityUtils.toString(entity, charSet);
            }
            LOG.info("请求执行结果：" + StringUtils.abbreviate(result, 256));
            return result;
        }
        catch (Exception e) {
            LOG.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

}
